#pragma once
#include <utility>
#include <tuple>
#include <iostream>
#include <string>
#include <sstream>
//template<typename TupleType,size_t n=std::tuple_size<TupleType>::value>
//void tuple_print(const TupleType& t)
//{
//	if constexpr (n > 1)
//	{
//		tuple_print<TupleType, n - 1>(t);
//	}
//	std::cout<<std::get<n - 1>(t) << std::endl;
//}

template<typename Tuple,size_t ... Indices>
void tuple_print_helper(const Tuple& t, std::index_sequence<Indices...> )
{
	((std::cout<<std::get<Indices>(t)<<std::endl) , ...);
}

template<typename ... Args>
void tuple_print(const std::tuple<Args...>& t)
{
	tuple_print_helper(t,std::index_sequence_for<Args...>());
}

//template<typename T,typename Base>
//Base* CreateObject()
//{
//	return new T;
//}

template<typename T,typename Container>
class Grid
{
public:
	Container container;
};


//Grid<void, void> voidgrid;

//template<class T,T v>
//struct my_integral_const
//{
//	static constexpr T value = v;
//	typedef T value_type;
//	typedef my_integral_const type;
//	constexpr operator value_type() const noexcept { return value; }
//	constexpr value_type operator()() const noexcept { return value; }
//};
//
//using true_type = my_integral_const<bool, true>;
//using false_type = my_integral_const<bool, false>;
//
//template<class _Ty>
//struct _Is_integral
//	: false_type
//{	// determine whether _Ty is integral
//};
//
//template<>
//struct _Is_integral<bool>
//	: true_type
//{	// determine whether _Ty is integral
//};
//
//template<>
//struct _Is_integral<char>
//	: true_type
//{	// determine whether _Ty is integral
//};
//
//template<class _Ty>
//struct my_is_integral
//	: _Is_integral<_Ty>::type
//{	// determine whether _Ty is integral
//};

template<typename T>
void process_impl(const T& t,std::true_type)
{
	std::string str = std::to_string(t);
	std::cout << "integral to string:" <<str<< std::endl;
}

template<typename T>
void process_impl(const T& t, std::false_type)
{
	std::stringstream ss;
	ss << t;
	std::cout << "not integral to string:" << ss.str() << std::endl;
}


template<typename T>
void process(const T& t)
{
	//process_impl(t,std::is_integral<T>::type());
	if constexpr (std::is_integral<T>::value)
	{
		std::string str = std::to_string(t);
		std::cout << "integral to string:" << str << std::endl;
	}
	else
	{
		std::stringstream ss;
		ss << t;
		std::cout << "not integral to string:" << ss.str() << std::endl;
	}
}
//std::enable_if_t --> enable_if<....,ret>::type
template<typename T1,typename T2>
std::enable_if_t<std::is_same_v<T1,T2>,bool> check_type(const T1& t1, const T2& t2)
{
	std::cout << "t1 and t2 are same type" << std::endl;
	return true;
}

template<typename T1, typename T2>
std::enable_if_t<!std::is_same_v<T1, T2>, bool> check_type(const T1& t1, const T2& t2)
{
	std::cout << "t1 and t2 are not same type" << std::endl;
	return false;
}


class IsDoable
{
public:
	void doit() const { std::cout << " parent call doit" << std::endl; }
};

class Derived:public IsDoable
{
public:
	void predoit() const { std::cout << " derived call predoit" << std::endl; }
};

//void call_doit(IsDoable* pDoable)
//{
//	if (pDoable)
//	{
//		pDoable->doit();
//	}
//}

//template<typename T>
//std::enable_if_t<std::is_base_of_v<IsDoable,T>,void> 
//call_doit(const T& t)
//{
//	t.predoit();
//	t.doit();
//}
//
//template<typename T>
//std::enable_if_t<!std::is_base_of_v<IsDoable, T>, void>
//call_doit(const T& t)
//{
//	std::cout << "cant call doit" << std::endl;
//}

template<typename T>
void call_doit([[maybe_unused]] const T&  t)
{
	if constexpr (std::is_base_of_v<IsDoable, T>)
	{
		t.doit();
	}
	else
	{
		std::cout << "cant call doit" << std::endl;
	}
}

